#include "MediaChannel.h"
#include "Manager.h"
#include "common.h"
#include "JsonAnalysis.h"

CMediaChannel::CMediaChannel(CManager *pMan)
:m_pClient(NULL)
,m_bExit(false)
,m_bValid(false)
,m_bFirstConnect(false)
,m_pMan(pMan)
{
	m_pSaveFile = NULL;
	m_usPacketNum = 0;
	m_bSaveVaild = false;
}

CMediaChannel::~CMediaChannel(void)
{
	Stop();
}

bool CMediaChannel::Start(void)
{
	m_bExit = false;
	m_bConnect = false;
	m_bValid = false;

	return StartThread();
}

void CMediaChannel::Stop(void)
{
	m_bExit = true;

	WaitForStop();

	if (m_pClient)
	{
		delete m_pClient;
		m_pClient = NULL;
	}

	while (m_lstRecvData.size())
	{
		LPRecvDataInfo pRecvData = NULL;

		{
			CAutoLock autoLock(&m_lockRecvData);
			pRecvData = (LPRecvDataInfo)m_lstRecvData.front();
			m_lstRecvData.pop_front();
		}

		if (pRecvData)
			ClearRecvData(pRecvData);			
	}
}

int CMediaChannel::SendDataToServer(int nCmd, const char *pData, int nDataLen)
{
	LPRecvDataInfo pSendData = new RecvDataInfo;
	if (pSendData)
	{
		pSendData->nCmd = nCmd;
		pSendData->nMsgLen = nDataLen;		

		if (pSendData->nMsgLen > 0)
		{
			pSendData->pData = new char[pSendData->nMsgLen];

			if (!pSendData->pData)
			{
				delete pSendData;
				pSendData = NULL;

				return -1;
			}

			memset(pSendData->pData, 0x00, pSendData->nMsgLen);
			memcpy(pSendData->pData, pData, pSendData->nMsgLen);
		}		

		CAutoLock autoLock(&m_lockSendData);
		m_lstSendData.push_back(pSendData);

		return 0;
	}

	return -1;
}

void CMediaChannel::ThreadProcMain(void)
{
	while (!m_bExit)
	{
		unsigned long ulNow = GetTimeStamp();

		HandleRecvData();

		HandleSendData();

		if (!m_bConnect && (ulNow - m_ulLastConnectTime) >= MAX_SEND_INTERVAL * 1000)
		{
			ConnectServer();
			m_ulLastConnectTime = ulNow;			
		}

		if (m_bConnect && (ulNow - m_ulLastSendTime) >= MAX_SEND_INTERVAL * 1000)
		{
			SendHeartbetMsg();
			m_ulLastSendTime = ulNow;
		}

		my_sleep(2);
	}
}

void CMediaChannel::OnRecvTcpServerDataNotify(const int nCmd, const int nPacketNum, const int nSendId, const char *szBuf, int nLen)
{
	LPRecvDataInfo pRecvData = new RecvDataInfo;
	if (pRecvData)
	{
		pRecvData->nSendId = nSendId;
		pRecvData->nMsgLen = nLen - HEADER_PACKET_LEN;
		pRecvData->nCmd = nCmd;
		pRecvData->nPacketNum = nPacketNum;

		if (pRecvData->nMsgLen > 0)
		{
			pRecvData->nMsgLen++;
			pRecvData->pData = new char[pRecvData->nMsgLen];

			if (!pRecvData->pData)
			{
				delete pRecvData;
				pRecvData = NULL;

				return;
			}

			memset(pRecvData->pData, 0x00, pRecvData->nMsgLen);
			memcpy(pRecvData->pData, szBuf + HEADER_PACKET_LEN, pRecvData->nMsgLen - 1);
		}		

		CAutoLock autoLock(&m_lockRecvData);
		m_lstRecvData.push_back(pRecvData);
	}
}

void CMediaChannel::OnDisConnTcpServerNotify(const int nType)
{
	m_bConnect = false;
	m_bValid = false;

	m_ulLastConnectTime = GetTimeStamp();

	RecvDataInfo *pRecvInfo = new RecvDataInfo;
	pRecvInfo->nCmd = MEDIACHANNEL_BREAK;

	m_pMan->PutRecvData(pRecvInfo);
}

void CMediaChannel::HandleRecvData(void)
{
	if (m_lstRecvData.size() > 0)
	{
		LPRecvDataInfo pRecvData = NULL;

		{
			CAutoLock autoLock(&m_lockRecvData);
			pRecvData = (LPRecvDataInfo)m_lstRecvData.front();
			m_lstRecvData.pop_front();
		}

		if (pRecvData)
		{
			switch (pRecvData->nCmd)
			{
			case CMD_T2S_CHANNELDECLAR_RSP:
				HandleChannelDeclareRsp(pRecvData);
				ClearRecvData(pRecvData);
				break;
			case WHITEBROAD_DATA:
				HandleWbData(pRecvData);
				ClearRecvData(pRecvData);
				break;
			case WHITEBROAD_FILE:
				HandleWbFile(pRecvData);
				ClearRecvData(pRecvData);
				break;
			case WHITEBROAD_FILE_START:
				HandleWBFileStart(pRecvData);
				ClearRecvData(pRecvData);
				break;
			case WHITEBROAD_FILE_END:
				HandleWBFileEnd(pRecvData);
				ClearRecvData(pRecvData);
				break;
			case SCREEN_DATA:
			case AUDIO_DATA:
				HandleScreenBroadcastData(pRecvData);
				break;
			default:
				ClearRecvData(pRecvData);
				break;
			}			
		}			
	}
}

void CMediaChannel::HandleSendData(void)
{
	if (m_lstSendData.size() > 0)
	{
		LPRecvDataInfo pSendData = NULL;

		{
			CAutoLock autoLock(&m_lockSendData);
			pSendData = (LPRecvDataInfo)m_lstSendData.front();
			m_lstSendData.pop_front();
		}

		if (pSendData)
		{
			SendData(pSendData->nCmd, pSendData->pData, pSendData->nMsgLen);

			ClearRecvData(pSendData);
		}			
	}
}

int CMediaChannel::ConnectServer(void)
{
	if (m_pClient)
	{
		delete m_pClient;
		m_pClient = NULL;
	}

	m_pClient = new CSocketTcpClient(this, true);

	if (!m_pClient)
		return -1;

	if (m_pClient->StartConnect(m_pMan->GetSvrIp(), m_pMan->GetSvrPort()))
	{
		m_ulLastSendTime = GetTimeStamp();	
		m_bConnect = true;

		SendChannelDeclare();

		return 0;
	}

	if (!m_bFirstConnect)
	{
		m_bFirstConnect = true;

		RecvDataInfo *pRecvInfo = new RecvDataInfo;
		pRecvInfo->nCmd = MEDIACHANNEL_CONNECT_FAIL;

		m_pMan->PutRecvData(pRecvInfo);
	}

	return -1;
}

int CMediaChannel::SendData(int nCmd, const char *pData, int nDataLen)
{
	if (!m_bConnect)
		return -1;
	
	return m_pClient->SendData(m_pMan->GetTerminalId(), nCmd, m_usPacketNum++, pData, nDataLen);
}

void CMediaChannel::ClearRecvData(RecvDataInfo *pRecvData)
{
	if (pRecvData)
	{
		if (pRecvData->pData)
		{
			delete [] pRecvData->pData;
			pRecvData->pData = NULL;
		}

		delete pRecvData;
		pRecvData = NULL;
	}
}

bool CMediaChannel::SendChannelDeclare(void)
{
	string strJson; 
	if (CJsonAnalysis::ChannelDeclare(strJson, DATA_CHANNEL, CODEC, 0))
	{
		int nLen = strJson.length();
		if (SendData(CMD_T2S_CHANNELDECLAR_REQ, strJson.c_str(), nLen) == nLen)
			return true;
	}

	return false;
}

bool CMediaChannel::SendHeartbetMsg(void)
{
	string strJson; 
	if (CJsonAnalysis::Heartbet(strJson))
	{
		int nLen = strJson.length();
		if (SendData(CMD_HEARTBEAT_REQ, strJson.c_str(), nLen) == nLen)
			return true;
	}

	return false;
}

void CMediaChannel::HandleChannelDeclareRsp(RecvDataInfo *pRecvData)
{
	int nResult(0);
	string strError;

	if (CJsonAnalysis::AnalysChannelDeclareRsp(pRecvData->pData, nResult, strError))
	{
		if (nResult == 200)
		{
			RecvDataInfo *pRecvInfo = new RecvDataInfo;
			pRecvInfo->nCmd = MEDIACHANNEL_CONNECT;

			m_pMan->PutRecvData(pRecvInfo);

			m_bValid = true;
		}
	}
}

void CMediaChannel::HandleWbData(RecvDataInfo *pRecvData)
{
	m_pMan->HandleRecvWBData(pRecvData->pData, pRecvData->nMsgLen);
}

void CMediaChannel::HandleWbFile(RecvDataInfo *pRecvData)
{
	if (m_pSaveFile)
		fwrite(pRecvData->pData, pRecvData->nMsgLen -1, 1, m_pSaveFile);
}

void CMediaChannel::HandleWBFileStart(RecvDataInfo *pRecvData)
{
	PhotoInfo *pInfo = (PhotoInfo *)pRecvData->pData;
	if (pInfo)
	{
		if (m_pSaveFile)
		{
			fclose(m_pSaveFile);
			m_pSaveFile = NULL;
		}

		char szFilePath[MAX_PATH] = {0};
		sprintf_s(szFilePath, "%s\\%d", m_pMan->GetFileSavePath().c_str(), pInfo->nTerminalId);

		if (!DirExist(szFilePath))
			CreateDir(szFilePath);

		char szSaveFilePath[MAX_PATH] = {0};
		sprintf_s(szSaveFilePath, "%s\\%s", szFilePath, pInfo->szFileName);

		int nRet = fopen_s(&m_pSaveFile, szSaveFilePath, "wb");
		if (nRet == 0)
			m_bSaveVaild = true;
		else
			m_bSaveVaild = false;
	}
}

void CMediaChannel::HandleWBFileEnd(RecvDataInfo *pRecvData)
{
	if (m_bSaveVaild && m_pSaveFile)
	{
		fclose(m_pSaveFile);
		m_pSaveFile = NULL;

		m_bSaveVaild = false;

		m_pMan->HandleRecvFileEnd();
	}
}

void CMediaChannel::HandleScreenBroadcastData(RecvDataInfo *pRecvData)
{
	m_pMan->PutScreenBroadcastData(pRecvData);
}

int CMediaChannel::SendFileData(const char *pData, int nDataLen)
{
	return SendData(WHITEBROAD_FILE, pData, nDataLen);
}

int CMediaChannel::SendFileEnd(void)
{
	 return SendData(WHITEBROAD_FILE, NULL, 0);
}
